
/************************************************************************************/
/*    Order Co.   2000-01-31                                                        */ 
/************************************************************************************/

#ifndef __RTCS_TIMER__H
#define __RTCS_TIMER__H

#include "RTCS_CMap.h"
#include "IClientBase.h"
#include "RTCSbaseObject.h"
#include "RTCSpdu.h"

//#include <time.h>

/* timer record block */
#ifndef VC
//##ModelId=3AAC6104000A
class RTCS_TRB : public RTCS_Node
#else
class RTCS_TRB : public RTCS_Node, public CObject
#endif
{
public:
	//##ModelId=3AAC6104005A
	RTCS_TRB(RTCS_CTuint lpTimerId, RTCS_CTuint lpOwner, RTCS_CTuint lpLeft, RTCS_CTuint lpAttr);

	//##ModelId=3AAC61040052
	RTCS_CTuint		owner;
	//##ModelId=3AAC61040048
	RTCS_CTuint		timerID;
	//##ModelId=3AAC6104003C
	RTCS_CTuint		attr;
	//##ModelId=3AAC6104002A
	RTCS_CTint		leftTimes;
	//##ModelId=3AAC61040021
	RTCS_CTint		expiredPoint;
};

typedef RTCS_List<RTCS_TRB> TYPE_TimerNodeList;
typedef RTCS_CMap<RTCS_CTuint, RTCS_CTuint, RTCS_TRB*, RTCS_TRB*> TYPE_TimerNodeHashTab;

#define COMM_TIMER_NUMBER	256

//##ModelId=3AAC61030301
class RTCS_MultiTimer
{
public:
	//##ModelId=3AAC6103039A
	RTCS_MultiTimer();
	//##ModelId=3AAC61030399
	~RTCS_MultiTimer();

	//##ModelId=3AAC61030398
	RTCS_CTuint		GenerateTimerId();
	//##ModelId=3AAC6103037A
	RTCS_CTuint		SetTimer(RTCS_CTuint owner, RTCS_CTuint delay, RTCS_CTuint attr = 0);
	//##ModelId=3AAC61030365
	RTCS_CTuint		GetExpiredTimer(RTCS_CTuint& owner, RTCS_CTuint& attr);
	//##ModelId=3AAC6103035C
	void			ClearTimer(RTCS_CTuint timerID);
	//##ModelId=3AAC6103035B
	void			Display();

private:
	//##ModelId=3AAC61030351
	TYPE_TimerNodeList		m_NodeList;
	//##ModelId=3AAC6103033F
	TYPE_TimerNodeHashTab	m_NodeHashTab;
	//##ModelId=3AAC61030335
	RTCS_Lock				m_CrLock;
	//##ModelId=3AAC6103032B
	RTCS_CTuint				IdGenerator;
	//##ModelId=3AAC6103031F
	RTCS_CTuint				lastTicks;
	//##ModelId=3AAC6103030D
	RTCS_CTuint				thisTicks;
};

/* queue with timer function */
typedef RTCS_Queue<RTCS_CTpdu> RTCS_PduQueue;

//##ModelId=3AAC61120172
class RTCS_PduTimerQueue: public RTCS_PduQueue
{
public:
	//##ModelId=3AAC611201B0
	RTCS_PduTimerQueue(RTCS_CTuint qSize = RTCS_QUEUESIZE);
	//##ModelId=3AAC611201AF
	~RTCS_PduTimerQueue();

	//##ModelId=3AAC611201AE
	RTCS_MultiTimer*	GetTimer();
	//##ModelId=3AAC611201A5
	RTCS_CTuint			Get(RTCS_CTpdu& elem);
	//##ModelId=3AAC6112019A
	RTCS_CTuint			TryGet(RTCS_CTpdu& elem);

private:
	//##ModelId=3AAC61120192
	RTCS_MultiTimer* pTimer;
};

/**************************\
** inline implementations **
\**************************/

inline RTCS_TRB::RTCS_TRB(RTCS_CTuint lpTimerId, RTCS_CTuint lpOwner, RTCS_CTuint lpLeft, RTCS_CTuint lpAttr)
	: timerID(lpTimerId),owner(lpOwner),leftTimes(lpLeft),attr(lpAttr)
{ 
	expiredPoint = GetTickCount() + lpLeft; 
}


inline RTCS_MultiTimer::RTCS_MultiTimer()
{
	IdGenerator = 0;
	m_NodeHashTab.InitHashTable(COMM_TIMER_NUMBER);
	lastTicks = GetTickCount();
}

inline RTCS_MultiTimer::~RTCS_MultiTimer()
{
	RTCS_TRB *node = m_NodeList.GetHead();
	while(node)
	{
		delete node;
		node = m_NodeList.GetHead();
	}
}

inline RTCS_CTuint RTCS_MultiTimer::GenerateTimerId()
{
	IdGenerator++;
	if(IdGenerator == 0)
		IdGenerator++;
	return IdGenerator;
}


inline RTCS_PduTimerQueue::RTCS_PduTimerQueue(RTCS_CTuint qSize)
	: RTCS_PduQueue(qSize)
{
	pTimer = new RTCS_MultiTimer;
}

inline RTCS_PduTimerQueue::~RTCS_PduTimerQueue()
{
	if( pTimer) delete pTimer;
}

inline RTCS_MultiTimer* RTCS_PduTimerQueue::GetTimer() 
{ 
	return pTimer; 
}

inline RTCS_CTuint RTCS_PduTimerQueue::Get(RTCS_CTpdu& elem)
{
	RTCS_CTuint owner, timerID, attr;
	while(1)
	{
		if(timerID=pTimer->GetExpiredTimer(owner,attr))
		{
			elem.receiverObj = owner;
			elem.senderObj = timerID;
			elem.status = attr;
			elem.messageID = EvtRTCS_IClientBase_Timer;
			return RTCS_Error_OK;
		}
		if(RTCS_PduQueue::TryGet(elem) == RTCS_Error_OK)
			return RTCS_Error_OK;
	}
	return RTCS_Error_ECTF_Fail;
}

inline RTCS_CTuint RTCS_PduTimerQueue::TryGet(RTCS_CTpdu& elem)
{
	RTCS_CTuint owner,timerID,attr;
	
	if(timerID=pTimer->GetExpiredTimer(owner,attr))
	{
		elem.receiverObj = owner;
		elem.senderObj = timerID;
		elem.status = attr;
		elem.messageID = EvtRTCS_IClientBase_Timer;
		return RTCS_Error_OK;
	}
	return RTCS_PduQueue::TryGet(elem);
}

#endif
